package com.freemodbus4j.core.codec;

import com.freemodbus4j.core.frame.ModbusFrame;
import io.netty.buffer.ByteBuf;

public abstract class AbstractModbusCodec<T, R> {

    /**
     * 解密
     */
    abstract public T decode(ByteBuf in);

    /**
     * 加密
     * @param r
     */
    abstract public void encode(R r, ByteBuf out);

    /**
     * 功能码独立处理
     *
     * 代码	名称	            寄存器PLC地址	    位/字操作	操作数量
     * 01	读线圈状态	    00001~09999	    位操作	单个或多个
     * 02	读离散输入状态	10001~19999	    位操作	单个或多个
     * 03	读保持寄存器	    40001~49999	    字操作	单个或多个
     * 04	读输入寄存器	    30001~39999	    字操作	单个或多个
     * 05	写单个线圈	    00001~09999	    位操作	单个
     * 06	写单个保持寄存器	40001~49999	    字操作	单个
     * 15	写多个线圈	    00001~09999	    位操作	多个
     * 16	写多个保持寄存器	40001~49999	    字操作	多个
     *
     * @param in
     */
    protected ModbusFrame.RequestBody body(ByteBuf in) {
        ModbusFrame.RequestBody body = ModbusFrame.RequestBody.builder()
                .func(in.readByte())
                .build();
        short address = in.readShort();
//        if (address < 0 || address > 9999) {
//            //非法数据地址
//            TcpFrame.Except except = TcpFrame.Except.builder()
//                    .header(request.getHeader())
//                    .func((byte)(request.getFunc() | 0x80))
//                    .exceptCode(ModbusSlaveCodeEnum.EXCEPT_02)
//                    .build();
//            request.setExcept(except);
//            return;
//        }
        switch (body.getFunc()) {
            case 1://读线圈状态           寄存器地址 00001~09999 位操作
            case 2://读离散输入状态        寄存器地址 10001~19999 位操作
            case 3:
            case 4: {
                body.setAddress(address);
                body.setQuantity(in.readShort());
            } break;
            case 5:
            case 6: {
                body.setAddress(address);
                body.setWriteData(new byte[] {
                        in.readByte(),
                        in.readByte(),
                });
            } break;
            case 8: {
                body.setChildFunc(in.readShort());
                body.setWriteData(new byte[] {
                        (byte) (in.readShort() >> 8 & 0xff),
                        (byte) (in.readShort() & 0xff),
                });
            } break;
            case 11:
            case 12: break;
            case 15:
            case 16: {
                body.setAddress(address);
                body.setQuantity(in.readShort());
                body.setByteCount(in.readByte());
                byte[] writeData = new byte[body.getByteCount()];
                in.readBytes(writeData);
                body.setWriteData(writeData);
            } break;
            case 17: break;
            default: return null;
        }
        return body;
    }

    protected void body(ModbusFrame.ResponseBody body, ByteBuf out) {
        out.writeByte(body.getFunc());
        switch (body.getFunc()) {
            case 1:
            case 2:
            case 3:
            case 4: {
                out.writeByte(body.getReturnLength());
                out.writeBytes(body.getData());
            } break;
            case 5:
            case 6: {
                out.writeShort(body.getInAddress());
                out.writeBytes(body.getInData());
            } break;
            case 8: {

            } break;
            case 11: break;
            case 12: break;
            case 15:
            case 16: {
                out.writeShort(body.getInAddress());
                out.writeShort(body.getRegisterCount());
            } break;
            case 17: break;
            default: break;
        }
    }
}
